/*
 * Individual.cpp
 *
 *  Created on: 27-12-2010
 *      Author: Przemek
 */

#include "world/Individual.hpp"
#include "world/ElementsVisitor.hpp"
#include "AI/thoughts/Thought.hpp"
#include "geometry/Line.hpp"
#include "utils/VectorUtils.hpp"
#include "utils/IndividualUtils.hpp"
#include "pch.hpp"
using namespace boost;

const float Individual::SIZE = 10.0f;

Individual::Individual() :
	brain(Brain()), genotype(Genotype()), state(genotype)
{
	bounds.setSize(Dimension(SIZE, SIZE));
}

Individual::Individual(const Vector& position) :
	brain(Brain()), genotype(Genotype()), state(genotype)
{
	bounds.setPosition(position);
	bounds.setSize(Dimension(SIZE, SIZE));
}

Individual::Individual(const Individual& other) :
	brain(other.brain), genotype(other.genotype), state(other.state)
{
	bounds = other.bounds;
}

Individual::Individual(const Genotype& genotype) :
	brain(Brain()), genotype(genotype), state(genotype)
{
	bounds.setSize(Dimension(SIZE, SIZE));
}

void Individual::accept(ElementsVisitor& visitor)
{
	visitor.visit(*this);
}

void Individual::updateWithDeltaTime(float deltaTimeInSeconds)
{
	state.updateWithDeltaTime(deltaTimeInSeconds);
	if(state.isDead())
	{
		setToDelete(true);
		return;
	}

	World::ElementsVector radarElements = World::getInstance().getElements(getRadar());
	IndividualUtils::removeUnvisibleElements(getPosition(), radarElements);
	scoped_ptr<Thought> newThought(brain.generateThought(*this, radarElements, deltaTimeInSeconds));

	Vector prevPosition = getPosition();
	newThought->execute(this);

	World::ElementsVector neighborhoodBarriers = World::getInstance().getNeighborhoodBarriers(
			getPosition());

	if(!World::BOUNDS.contains(getPosition()) || IndividualUtils::intersectsAnyBarrier(getBounds(),
			neighborhoodBarriers))
	{
		setPosition(prevPosition);
	}
}

Brain& Individual::getBrain()
{
	return brain;
}

State& Individual::getState()
{
	return state;
}

const State& Individual::getState() const
{
	return state;
}

Genotype& Individual::getGenotype()
{
	return genotype;
}

const Genotype& Individual::getGenotype() const
{
	return genotype;
}

const Vector& Individual::getLookDirection() const
{
	return state.getLookDirection();
}

CircleSlice Individual::getRadar() const
{
	const Vector& position = bounds.getCenter();
	float radius = genotype.getSightDistance();
	float openingAngle = MathUtils::toRadians(genotype.getSightRange());
	float angle = getLookDirection().getAngleInRadians();

	return CircleSlice(position, radius, angle, openingAngle);
}
